package org.chs.ts.batch.thread;

import org.apache.commons.lang.StringUtils;

import org.chs.ts.base.batch.log.entity.BatchClearBasicLog;
import org.chs.ts.batch.factory.BatchThreadFactory;
import org.chs.ts.batch.factory.SernoFactory;
import org.chs.ts.batch.service.IBatchClearBasicLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.RejectedExecutionException;



/**
 * @Compay 盛唐天行
 * @Author: wuwei
 * @Censor By wuwei
 * @Sence 2023/1/5 17:24
 * @Modify 2023/1/5 17:24
 * @Description 批量处理 线程池控制类
 */
@Configuration
@ConditionalOnBean(BatchThreadPoolProperties.class)
public class BatchThreadPool {
    private static final Logger log = LoggerFactory.getLogger(BatchThreadPool.class);

    /**
     * 保存 BatchPoolExecutor 线程池
     */
    private static ThreadPoolTaskExecutor threadPoolTaskExecutor;

    /**
     * 线程池参数
     */
    @Resource
    BatchThreadPoolProperties batchThreadPoolProperties;

    @Resource
    IBatchClearBasicLogService clearBasicLogServiceImpl;

    /**
     * Spring 托管线程池 初始化
     *
     * @return 任务执行器
     */
    @Bean(name = "threadPoolBatchTaskExecutor")
    public ThreadPoolTaskExecutor initBatchThreadPool() {
        log.info("initBatchThreadPool init thread pool begin");

        // 判断是否 存在分片任务线程池则返回当前线程池
        if (isInitialized()) {
            log.info("BatchThreadPool already exists initBatchThreadPool method execution end!");
            return threadPoolTaskExecutor;
        }

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        // 设置核心线程数
        log.info("CorePoolSize:[{}]", batchThreadPoolProperties.getCorePoolSize());
        executor.setCorePoolSize(batchThreadPoolProperties.getCorePoolSize());

        // 设置最大线程数
        log.info("MaxPoolSize:[{}]", batchThreadPoolProperties.getMaxPoolSize());
        executor.setMaxPoolSize(batchThreadPoolProperties.getMaxPoolSize());

        // 设置队列容量
        log.info("QueueCapacity:[{}]", batchThreadPoolProperties.getQueueCapacity());
        executor.setQueueCapacity(batchThreadPoolProperties.getQueueCapacity());

        // 设置线程空闲时间(秒)
        log.info("KeepAliveSeconds:[{}]", batchThreadPoolProperties.getKeepAliveSeconds());
        executor.setKeepAliveSeconds(batchThreadPoolProperties.getKeepAliveSeconds());

        // 创建自定义线程工厂
        /**
         * 线程工厂
         */
        BatchThreadFactory batchThreadFactory = new BatchThreadFactory();
        /**
         * 线程组
         */
        ThreadGroup threadGroup = new ThreadGroup(BatchThreadPool.class.getName());

        // 设置线程名称前缀
        String namePrefix = StringUtils.isBlank(batchThreadPoolProperties.getNamePrefix()) ? null : modifyNamePrefix(batchThreadPoolProperties.getNamePrefix());
        log.info("ThreadNamePrefix:[{}]",namePrefix);
        batchThreadFactory.setThreadNamePrefix(namePrefix);
        // 设置线程工厂 线程组
        batchThreadFactory.setThreadGroup(threadGroup);

        // 设置拒绝策略
        executor.setRejectedExecutionHandler((r, executor1) -> {
            BatchClearBasicLog obj = createCLearBasicLog();
            obj.setRtnDesc(obj.getRtnDesc()+" MaxPoolSize:"+batchThreadPoolProperties.getMaxPoolSize());
            clearBasicLogServiceImpl.save(obj);
            throw new RejectedExecutionException("中间业务系统线程拒绝");

        });

        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);

        // 设置线程组
        // 增加线程组配置 可通过线程组限制进行 线程获取
        executor.setThreadGroup(threadGroup);

        // 留存线程池
        threadPoolTaskExecutor = executor;

        log.info("initBatchThreadPool init thread pool end");

        return executor;
    }


    private BatchClearBasicLog createCLearBasicLog() {
        BatchClearBasicLog obj = new BatchClearBasicLog();
        obj.setLogSerno(SernoFactory.createSerno("threadrejected"));
        obj.setTaskExecid("");
        obj.setTaskGroup("");
        obj.setTaskId("");
        obj.setStepNo("");
        obj.setTaskDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        obj.setExecStatus("4");
        obj.setExecDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        obj.setShouldExecDate("");
        obj.setTargetCode("");
        obj.setProdCode("");
        obj.setStartTime(new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
        obj.setEndTime(new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()));
        obj.setThreadUuid("");
        obj.setServerName("");
        obj.setServerIp("");
        obj.setRtnCode("999999");
        obj.setRtnDesc("线程拒绝");

        return obj;
    }
    /**
     * 执行给定的任务
     * @param task 需要执行的任务
     */
    public static void execute(Runnable task){
        threadPoolTaskExecutor.execute(task);
    }

    /*
     * 执行给定的任务(返回执行结果)
     * @param task
     * @return
     */
//    public static Future<?> submit(Runnable task){
//        return threadPoolTaskExecutor.submit(task);
//    }

    /*
     * 提交要执行的返回值的任务
     */
//    public static<T> Future<T> submit(Callable<T> task){
//        return threadPoolTaskExecutor.submit(task);
//    }

    /*
     * 返回核心线程数 线程池未初始化返回 -1
     * @return 核心线程数
     */
//    public static int getCorePoolSize(){
//        if(!isInitialized()){
//            return -1;
//        }
//
//        return threadPoolTaskExecutor.getThreadPoolExecutor().getCorePoolSize();
//    }

    /**
     * 返回最大线程数，线程池未初始化返回 -1
     */
    public static int getMaximumPoolSize(){
        if (!isInitialized()) {
            return -1;
        }
        return threadPoolTaskExecutor.getThreadPoolExecutor().getMaximumPoolSize();
    }

    /**
     * 返回线程池中当前线程数，线程池未初始化返回-1
     */
//    public static int getPoolSize(){
//        if (!isInitialized()) {
//            return -1;
//        }
//        return threadPoolTaskExecutor.getThreadPoolExecutor().getPoolSize();
//    }

    /**
     * 返回当前执行线程数，线程池未初始化返回 -1
     */
    public static int getActiveCount(){
        if (!isInitialized()) {
            return -1;
        }
        return threadPoolTaskExecutor.getThreadPoolExecutor().getActiveCount();
    }

    /**
     * 返回线程任务队列数 线程池未初始化返回 -1
     */
    public static int getQueueCount(){
        if (!isInitialized()) {
            return -1;
        }
        return threadPoolTaskExecutor.getThreadPoolExecutor().getQueue().size();
    }

    /**
     * 返回线程池最大队列数  线程池未初始化返回 -1
     */
    public static int getQueueCapacity(){
        if (!isInitialized()) {
            return -1;
        }
        return threadPoolTaskExecutor.getThreadPoolExecutor().getQueue().remainingCapacity();
    }

    /**
     * 当前线程池 可使用线程
     * @return 可使用线程数
     */
    public static int getIdleThreadCount(){
        // 空闲线程数 = (最大线程数+最大队列数)-(活动线程数+队列线程数)
        int idleCount =(getMaximumPoolSize() + getQueueCapacity()) -(getActiveCount()+getQueueCount());
        log.info( "允许使用线程:[{}] 最大线程数:[{}] 最大队列数:[{}] 活动线程数:[{}] 队列线程数:[{}]",
                idleCount,
                getMaximumPoolSize(),
                getQueueCapacity(),
                getActiveCount(),
                getQueueCount());
        return idleCount;
    }

    /*
     * 获取线程池中的Thread 未设置线程组返回 null
     * @return 线程组
     */
//    public static Thread[] listThread(){
//        if (threadGroup == null) {
//            return null;
//        }
//
//        int threadSize = (int)(threadGroup.activeCount()*1.2); // 这里乘以1.2为等待队列占有总线程数系数
//        Thread[] arrayThread = new Thread[threadSize];
//
//        int putCount = threadGroup.enumerate(arrayThread,true);
//
//        // 去除数组中的空的对象
//        if(putCount<threadSize){
//            int index = 0;
//            Thread[] realThread = new Thread[putCount];
//            for (Thread thread : arrayThread) {
//                if (thread!=null) {
//                    realThread[++index] = thread;
//                }
//            }
//            arrayThread = realThread;
//        }
//        return arrayThread;
//
//    }

    /*
     * 返回当前存货线程队列
     * @return 线程组
     */
//    public static HashSet<Thread> getWorkThreads(){
//        if(batchThreadFactory == null){
//            return null;
//        }
//
//        return batchThreadFactory.getSliceWorkThreads();
//    }

    /*
     * 清理未工作线程
     * @return 清理掉的线程数
     */
//    public static int cleanWorkThread(){
//        if(batchThreadFactory == null){
//            return 0;
//        }
//
//        HashSet<Thread> workThreads = batchThreadFactory.getSliceWorkThreads();
//        int count = 0;
//        for (Thread workThread : workThreads) {
//            if(workThread.getState() == Thread.State.TERMINATED){
//                log.info("清理线程 ThreadNo:{[]}",workThread.getId());
//                workThreads.remove(workThread);
//                count++;
//            }
//        }
//        return count;
//    }

    /*
     * 返回 threadGroup
     */
//    public static ThreadGroup getThreadGroup(){
//        return threadPoolTaskExecutor.getThreadGroup();
//    }





    /**
     * 确认 线程名称前缀 末尾是否包含'-'
     */
    private String modifyNamePrefix(String namePrefix) {
        // 结尾无中划线则进行添加
        char endChar = '-';
        if (0 > namePrefix.lastIndexOf(endChar) || namePrefix.lastIndexOf(endChar) != namePrefix.length() - 1) {
            namePrefix += endChar;
        }
        return namePrefix;
    }

    /**
     * 判断 是否存在分片任务线程池
     */
    public static boolean isInitialized() {

        if (threadPoolTaskExecutor == null) {
           return false;
        } else {
            threadPoolTaskExecutor.getThreadPoolExecutor();
        }
        return true;
    }
}
